package com.neuronbit.businessflow.intellij.editor.palette.impl;

import com.intellij.designer.LightToolWindowContent;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTabbedPane;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.mxGraphOutline;
import com.mxgraph.swing.util.mxGraphTransferable;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxResources;
import com.mxgraph.view.mxGraph;
import com.neuronbit.businessflow.intellij.editor.swing.GuiEditor;
import com.neuronbit.businessflow.intellij.editor.swing.editor.EditorPalette;
import com.neuronbit.businessflow.intellij.model.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

import static java.util.Objects.requireNonNull;

/**
 * The type Palette window.
 */
public class PaletteWindow extends JPanel implements LightToolWindowContent, DataProvider {
    private final Project myProject;
    private GuiEditor myDesigner;
    //    private final ArrayList<PaletteGroupHeader> myGroupHeaders = new ArrayList<>();
    private final JScrollPane myScrollPane = ScrollPaneFactory.createScrollPane();
    private final MyToolWindowPanel myToolWindowPanel = new MyToolWindowPanel();
    //    private final Set<PaletteGroup> myGroups = new HashSet<>();
    private final mxGraphComponent graphComponent;
    private static final String IMAGES = "/com/mxgraph/editor/swing/images/";
    /**
     * The Graph outline.
     */
    protected mxGraphOutline graphOutline;
    /**
     * The Library pane.
     */
    protected JTabbedPane libraryPane;

    /**
     * Instantiates a new Palette window.
     *
     * @param project  the project
     * @param designer the designer
     */
    public PaletteWindow(Project project, GuiEditor designer) {
        myProject = project;
        myDesigner = designer;
        // Creates the library pane that contains the tabs with the palettes
        setLayout(new BorderLayout());
        myScrollPane.setBorder(null);
        //Scroll会导致title无法显示出来
        libraryPane = new JBTabbedPane(SwingConstants.TOP/*, JTabbedPane.SCROLL_TAB_LAYOUT*/);
        // Creates the graph outline component
        graphComponent = designer.getGraphComponent();
        graphOutline = new mxGraphOutline(graphComponent);

        myToolWindowPanel.setFirstComponent(libraryPane);
        myToolWindowPanel.setSecondComponent(graphOutline);

        add(myToolWindowPanel, BorderLayout.CENTER);

        // Installs the popup menu in the outline
        graphOutline.addMouseListener(new MouseAdapter() {

            /**
             *
             */
            public void mousePressed(MouseEvent e) {
                // Handles context menu on the Mac where the trigger is on mousepressed
                mouseReleased(e);
            }

            /**
             *
             */
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    showOutlinePopupMenu(e);
                }
            }
        });

        // Handles mouse wheel events in the outline and graph component
        graphOutline.addMouseWheelListener(designer.getWheelTracker());
        graphComponent.addMouseWheelListener(designer.getWheelTracker());

        // Creates the shapes palette
        EditorPalette shapesPalette = insertPalette(mxResources.get("shapes"));
        EditorPalette imagesPalette = insertPalette(mxResources.get("images"));
        EditorPalette symbolsPalette = insertPalette(mxResources.get("symbols"));

        mxGraph graph = graphComponent.getGraph();
        // Sets the edge template to be used for creating new edges if an edge
        // is clicked in the shape palette
        shapesPalette.addListener(mxEvent.SELECT, (sender, evt) -> {
            Object tmp = evt.getProperty("transferable");

            if (tmp instanceof mxGraphTransferable) {
                mxGraphTransferable t = (mxGraphTransferable) tmp;
                Object cell = t.getCells()[0];

                if (graph.getModel().isEdge(cell)) {
                    ((GuiEditor.CustomGraph) graph).setEdgeTemplate(cell);
                }
            }
        });

        // Adds some template cells for dropping into the graph
//        shapesPalette
//                .addTemplate(
//                        "Container",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "swimlane.png"))),
//                        "swimlane", 280, 200, "Container");
//        shapesPalette
//                .addTemplate(
//                        "Icon",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rounded.png"))),
//                        "icon;image=" + IMAGES + "wrench.png", 40, 40, "Icon");
//        shapesPalette
//                .addTemplate(
//                        "Label",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rounded.png"))),
//                        "label;image=" + IMAGES + "gear.png", 120, 40, "Label");
//        shapesPalette
//                .addTemplate(
//                        "Rectangle",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rectangle.png"))),
//                        null, 120, 40, "");
        shapesPalette
                .addTemplate(
                        "Auto Task",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rounded.png"))),
                        "rounded=1", 120, 40, new AutoTask());
        shapesPalette
                .addTemplate(
                        "Stateful Task",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "doublerectangle.png"))),
                        "rectangle;shape=doubleRectangle", 120, 40, new StatefulTask());
//        shapesPalette
//                .addTemplate(
//                        "Ellipse",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "ellipse.png"))),
//                        "ellipse", 60, 60, "");
//        shapesPalette
//                .addTemplate(
//                        "Double Ellipse",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "doubleellipse.png"))),
//                        "ellipse;shape=doubleEllipse", 60, 60, "");
//        shapesPalette
//                .addTemplate(
//                        "Triangle",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "triangle.png"))),
//                        "triangle", 50, 70, "");
        shapesPalette
                .addTemplate(
                        "Decision",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rhombus.png"))),
                        "rhombus", 70, 70, new Decision());
//        shapesPalette
//                .addTemplate(
//                        "Horizontal Line",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "hline.png"))),
//                        "line", 160, 10, "");
//        shapesPalette
//                .addTemplate(
//                        "Hexagon",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "hexagon.png"))),
//                        "shape=hexagon", 100, 60, "");
//        shapesPalette
//                .addTemplate(
//                        "Cylinder",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "cylinder.png"))),
//                        "shape=cylinder", 50, 60, "");
//        shapesPalette
//                .addTemplate(
//                        "Actor",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "actor.png"))),
//                        "shape=actor", 40, 50, "");
//        shapesPalette
//                .addTemplate(
//                        "Cloud",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "cloud.png"))),
//                        "ellipse;shape=cloud", 60, 50, "");

//        shapesPalette
//                .addEdgeTemplate(
//                        "Straight",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "straight.png"))),
//                        "straight", 120, 120, "");
//        shapesPalette
//                .addEdgeTemplate(
//                        "Horizontal Connector",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "connect.png"))),
//                        null, 100, 100, "");
//        shapesPalette
//                .addEdgeTemplate(
//                        "Vertical Connector",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "vertical.png"))),
//                        "vertical", 100, 100, "");
//        shapesPalette
//                .addEdgeTemplate(
//                        "Entity Relation",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "entity.png"))),
//                        "entity", 100, 100, "");
//        shapesPalette
//                .addEdgeTemplate(
//                        "Arrow",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "arrow.png"))),
//                        "arrow", 120, 120, "");

        imagesPalette
                .addTemplate(
                        "Bell",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "bell.png"))),
                        "image;image=" + IMAGES + "bell.png", 40, 40, "Bell");
        imagesPalette
                .addTemplate(
                        "Box",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "box.png"))),
                        "image;image=" + IMAGES + "box.png",
                        40, 40, "Box");
        imagesPalette
                .addTemplate(
                        "Cube",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "cube_green.png"))),
                        "image;image=" + IMAGES + "cube_green.png",
                        40, 40, "Cube");
        imagesPalette
                .addTemplate(
                        "User",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "dude3.png"))),
                        "roundImage;image=" + IMAGES + "dude3.png",
                        40, 40, "User");
        imagesPalette
                .addTemplate(
                        "Earth",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "earth.png"))),
                        "roundImage;image=" + IMAGES + "earth.png",
                        40, 40, "Earth");
        imagesPalette
                .addTemplate(
                        "Gear",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "gear.png"))),
                        "roundImage;image=" + IMAGES + "gear.png",
                        40, 40, "Gear");
        imagesPalette
                .addTemplate(
                        "Home",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "house.png"))),
                        "image;image=" + IMAGES + "house.png",
                        40, 40, "Home");
        imagesPalette
                .addTemplate(
                        "Package",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "package.png"))),
                        "image;image=" + IMAGES + "package.png",
                        40, 40, "Package");
        imagesPalette
                .addTemplate(
                        "Printer",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "printer.png"))),
                        "image;image=" + IMAGES + "printer.png",
                        40, 40, "Printer");
        imagesPalette
                .addTemplate(
                        "Server",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "server.png"))),
                        "image;image=" + IMAGES + "server.png",
                        40, 40, "Server");
        imagesPalette
                .addTemplate(
                        "Workplace",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "workplace.png"))),
                        "image;image=" + IMAGES + "workplace.png",
                        40, 40, "Workplace");
        imagesPalette
                .addTemplate(
                        "Wrench",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "wrench.png"))),
                        "roundImage;image=" + IMAGES + "wrench.png",
                        40, 40, "Wrench");

//        symbolsPalette
//                .addTemplate(
//                        "Finally Handler",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "cancel_end.png"))),
//                        "roundImage;image=" + IMAGES + "cancel_end.png",
//                        50, 50, new FinallyHandler());
//        symbolsPalette
//                .addTemplate(
//                        "Exception Handler",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "error.png"))),
//                        "roundImage;image=" + IMAGES + "error.png",
//                        50, 50, new ExceptionHandler());
        shapesPalette
                .addTemplate(
                        "Switch",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "inclusive.png"))),
                        "rhombusImage;image=" + IMAGES + "inclusive.png",
                        50, 50, new SwitchTask());
//        symbolsPalette
//                .addTemplate(
//                        "Exception Handler",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "link.png"))),
//                        "roundImage;image=" + IMAGES + "link.png",
//                        50, 50, new ExceptionHandler());
        shapesPalette
                .addTemplate(
                        "Fork",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "fork.png"))),
                        "rhombusImage;image=" + IMAGES + "fork.png",
                        50, 50, new Fork());
        shapesPalette
                .addTemplate(
                        "Join",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "merge.png"))),
                        "rhombusImage;image=" + IMAGES + "merge.png",
                        50, 50, new Join());
//        symbolsPalette
//                .addTemplate(
//                        "Message",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "message.png"))),
//                        "roundImage;image=" + IMAGES + "message.png",
//                        50, 50, "Message");
//        symbolsPalette
//                .addTemplate(
//                        "Multiple",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "multiple.png"))),
//                        "roundImage;image=" + IMAGES + "multiple.png",
//                        50, 50, "Multiple");
//        symbolsPalette
//                .addTemplate(
//                        "Rule",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "rule.png"))),
//                        "roundImage;image=" + IMAGES + "rule.png",
//                        50, 50, "Rule");
        shapesPalette
                .addTemplate(
                        "Start",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "event.png"))),
                        "roundImage;image=" + IMAGES + "event.png",
                        50, 50, new Start());
        shapesPalette
                .addTemplate(
                        "End",
                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "terminate.png"))),
                        "roundImage;image=" + IMAGES + "terminate.png",
                        50, 50, new End());
//        symbolsPalette
//                .addTemplate(
//                        "Timer",
//                        new ImageIcon(requireNonNull(GuiEditor.class.getResource(IMAGES + "timer.png"))),
//                        "roundImage;image=" + IMAGES + "timer.png",
//                        50, 50, "Timer");
    }

    /**
     * Gets library pane.
     *
     * @return the library pane
     */
    public JTabbedPane getLibraryPane() {
        return libraryPane;
    }

    /**
     * Gets graph outline.
     *
     * @return the graph outline
     */
    public mxGraphOutline getGraphOutline() {
        return graphOutline;
    }

    /**
     * Show outline popup menu.
     *
     * @param e the e
     */
    protected void showOutlinePopupMenu(MouseEvent e) {
        Point pt = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(),
                graphComponent);
        JCheckBoxMenuItem item = new JCheckBoxMenuItem(
                mxResources.get("magnifyPage"));
        item.setSelected(graphOutline.isFitPage());

        item.addActionListener(new ActionListener() {
            /**
             *
             */
            public void actionPerformed(ActionEvent e) {
                graphOutline.setFitPage(!graphOutline.isFitPage());
                graphOutline.repaint();
            }
        });

        JCheckBoxMenuItem item2 = new JCheckBoxMenuItem(
                mxResources.get("showLabels"));
        item2.setSelected(graphOutline.isDrawLabels());

        item2.addActionListener(new ActionListener() {
            /**
             *
             */
            public void actionPerformed(ActionEvent e) {
                graphOutline.setDrawLabels(!graphOutline.isDrawLabels());
                graphOutline.repaint();
            }
        });

        JCheckBoxMenuItem item3 = new JCheckBoxMenuItem(
                mxResources.get("buffering"));
        item3.setSelected(graphOutline.isTripleBuffered());

        item3.addActionListener(new ActionListener() {
            /**
             *
             */
            public void actionPerformed(ActionEvent e) {
                graphOutline.setTripleBuffered(!graphOutline.isTripleBuffered());
                graphOutline.repaint();
            }
        });

        JPopupMenu menu = new JPopupMenu();
        menu.add(item);
        menu.add(item2);
        menu.add(item3);
        menu.show(graphComponent, pt.x, pt.y);

        e.consume();
    }

    /**
     * Insert palette editor palette.
     *
     * @param title the title
     * @return the editor palette
     */
    public EditorPalette insertPalette(String title) {
        final EditorPalette palette = new EditorPalette();
        final JScrollPane scrollPane = new JBScrollPane(palette);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        libraryPane.add(title, scrollPane);

        // Updates the widths of the palettes if the container size changes
        libraryPane.addComponentListener(new ComponentAdapter() {
            /**
             *
             */
            public void componentResized(ComponentEvent e) {
                int w = scrollPane.getWidth() - scrollPane.getVerticalScrollBar().getWidth();
                palette.setPreferredWidth(w);
            }

        });

        return palette;
    }

    @Override
    public void dispose() {

    }

    @Override
    public @Nullable Object getData(@NotNull @NonNls String s) {
        return null;
    }

    /**
     * Refresh palette if changed.
     *
     * @param designer the designer
     */
    public void refreshPaletteIfChanged(GuiEditor designer) {
//        removePaletteProviderListener();
        myDesigner = designer;
        if (designer != null) {
//            addPaletteProviderListener();
        }

//        VirtualFile file = designer == null ? null : designer.getFile();
//        Set<PaletteGroup> currentGroups = new HashSet<>(collectCurrentGroups(file));
//        if (!currentGroups.equals(myGroups)) {
//            refreshPalette(file);
//        }
    }

    private void refreshPalette(@Nullable VirtualFile selectedFile) {
//        for (PaletteGroupHeader groupHeader : myGroupHeaders) {
//            groupHeader.getComponentList().removeListSelectionListener(myListSelectionListener);
//        }
//        String[] oldTabNames = collectTabNames(myGroups);
//        myTabbedPane.removeAll();
//        myGroupHeaders.clear();
//        myGroups.clear();
//
//        final ArrayList<PaletteGroup> currentGroups = collectCurrentGroups(selectedFile);
//        String[] tabNames = collectTabNames(currentGroups);
//        if (tabNames.length == 1) {
//            if (oldTabNames.length != 1) {
//                remove(myTabbedPane);
//                add(myScrollPane);
//            }
//
//            PaletteContentWindow contentWindow = new PaletteContentWindow();
//            myScrollPane.getViewport().setView(contentWindow);
//
//            for (PaletteGroup group : currentGroups) {
//                addGroupToControl(group, contentWindow);
//            }
//
//            final JComponent view = (JComponent)myScrollPane.getViewport().getView();
//            if (view != null) {
//                view.revalidate();
//                for (Component component : view.getComponents()) {
//                    component.revalidate();
//                }
//            }
//        }
    }

    private class MyToolWindowPanel extends Splitter implements DataProvider {
        /**
         * Instantiates a new My tool window panel.
         */
        MyToolWindowPanel() {
            super(true, 0.7f);
        }

        @Override
        @Nullable
        public Object getData(@NotNull @NonNls String dataId) {
//            if (GuiEditor.DATA_KEY.is(dataId) && myComponentTree != null) {
//                return myComponentTree.getData(dataId);
//            }
            return null;
        }
    }
}
